<script lang="tsx" setup>
import TabsFormManager from "./tabs-form-manager.ts"
import {nextTick, ref, watch} from "vue"

/** 定义组件属性 */
const propsData = defineProps<{
  tabsFormModel: TabsFormManager
}>()

/** 定义事件发射器 */
const emit = defineEmits<{
  (e: 'tabs-form-change'): void
  (e: 'tabs-form-click', data: any): void
}>()

/** 组件数据 */
const tabsFormModel = ref<TabsFormManager>()
const tabsFormData = ref()
const activeBarStyle = ref({
  width: '0px',
  transform: 'translateX(0px)'
})

/**
 * 处理标签点击事件
 */
const handleClick = (item: any) => {
  tabsFormData.value = item.label
  emit('tabs-form-click', item)
  updateActiveBar()
}

/**
 * 获取当前选中的标签数据
 * @returns 当前标签数据
 */
const getTabsFormData = () => {
  return tabsFormModel.value?.els.find((item: any) => {
    return item.label === tabsFormData.value
  })
}

/**
 * 设置当前选中的标签
 * @param data 标签名称
 */
const setTabsFormData = (data: any) => {
  tabsFormData.value = data
  updateActiveBar()
}

/** 初始化数据 */
const initData = () => {
  if (tabsFormModel.value?.initData) {
    setTabsFormData(tabsFormModel.value.initData)
  } else {
    setTabsFormData(tabsFormModel.value?.els[0].label)
  }
}

/**
 * 更新激活条位置和宽度
 */
const updateActiveBar = () => {
  nextTick(() => {
    const activeTab: any = document.querySelector('.custom-tab-item.active')
    if (activeTab) {
      const width = activeTab.clientWidth
      const left = activeTab.offsetLeft
      activeBarStyle.value = {
        width: `${width}px`,
        transform: `translateX(${left}px)`
      }
    }
  })
}

/**
 * 计算渲染内容
 * @param item 项目数据
 * @param data 渲染数据
 * @returns 渲染元素
 */
const computedRender = (item: any, data: any) => {
  return item.renderFn(data)
}

/** 监听tabs模型变化 */
watch(() => propsData.tabsFormModel, (newValue: any) => {
  if (newValue) {
    tabsFormModel.value = newValue
    initData()
  }
}, {
  deep: true,
  immediate: true
})

/** 监听选中标签变化 */
watch(() => tabsFormData.value, () => {
  emit("tabs-form-change")
})

/** 暴露方法给父组件 */
defineExpose({
  getTabsFormData,
  setTabsFormData
})
</script>

<template>
  <div class="tabs-form">
    <div class="custom-tabs">
      <div class="custom-tabs-header">
        <div
            v-for="(item, index) in tabsFormModel?.els"
            :key="index"
            :class="['custom-tab-item', { 'active': item.label === tabsFormData }]"
            @click="handleClick(item)"
        >
          <template v-if="tabsFormModel?.renderFn">
            <component :is="computedRender(tabsFormModel, item)"/>
          </template>
          <template v-else>
            <span class="tab-content">
              <span class="tab-label">{{ item.label }}</span>
              <span v-if="item.total !== undefined" class="custom-tab-total">
                {{ item.total > 99 ? '99+' : item.total }}
              </span>
            </span>
          </template>
        </div>
        <!-- 激活条 -->
        <div :style="activeBarStyle" class="custom-tabs-active-bar"></div>
      </div>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.tabs-form {
  .custom-tabs {
    padding: 0 10px;
    border: 1px solid #e4e7ed;
    border-radius: 8px;
    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
    background-color: #ffffff;
    overflow: hidden;

    .custom-tabs-header {
      position: relative;
      display: flex;
      align-items: center;
      min-height: 40px;
      box-sizing: border-box;
      background-color: #ffffff;

      .custom-tab-item {
        padding: 0 20px;
        height: 100%;
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        font-size: 14px;
        color: #606266;
        position: relative;
        white-space: nowrap;
        transition: color 0.3s ease;

        &:hover {
          color: #409eff;
        }

        &.active {
          color: #409eff;
          font-weight: 600;
        }

        .tab-content {
          display: flex;
          align-items: center;
          position: relative;
        }

        .custom-tab-total {
          display: flex;
          align-items: center;
          justify-content: center;
          margin-left: 10px;
          margin-bottom: 10px;
          width: 23px;
          height: 23px;
          border-radius: 11px;
          background-color: #e95655;
          color: #ffffff;
          font-size: 12px;
          font-weight: normal;
          line-height: 18px;
        }
      }

      .custom-tabs-active-bar {
        position: absolute;
        bottom: 0;
        left: 0;
        height: 3px;
        background: linear-gradient(90deg, #4895ef, #4361ee);
        border-radius: 3px 3px 0 0;
        transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
      }
    }
  }
}
</style>